package com.x.provider.general.service.cms;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.x.core.domain.SuggestionTypeEnum;
import com.x.core.utils.ApiAssetUtil;
import com.x.core.utils.BeanUtil;
import com.x.core.utils.JsonUtil;
import com.x.core.web.api.R;
import com.x.core.web.page.PageHelper;
import com.x.core.web.page.PageList;
import com.x.kafka.MqTemplate;
import com.x.provider.api.general.enums.ContentStatusEnum;
import com.x.provider.api.general.enums.ContentTitleItemTypeEnum;
import com.x.provider.api.general.enums.GeneralErrorEnum;
import com.x.provider.api.general.model.dto.cms.ContentCreateReqDTO;
import com.x.provider.api.general.model.dto.cms.ContentMyReqDTO;
import com.x.provider.api.general.model.dto.cms.ContentMyTotalReqDTO;
import com.x.provider.api.oss.enums.ContentGroupTypeEnum;
import com.x.provider.api.oss.enums.MimeTypeEnum;
import com.x.provider.api.oss.model.dto.green.AddGreenNotifyRequestDTO;
import com.x.provider.api.oss.model.dto.green.ContentGreenResultDTO;
import com.x.provider.api.oss.model.dto.green.GreenRequestDTO;
import com.x.provider.api.oss.service.GreenRpcService;
import com.x.provider.api.oss.service.VodRpcService;
import com.x.provider.general.constants.Constants;
import com.x.provider.general.mapper.*;
import com.x.provider.general.model.domain.cms.*;
import com.x.provider.general.model.query.cms.*;
import com.x.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ContentServiceImpl implements ContentService{

    private final ContentMapper contentMapper;
    private final ContentMediaMapper contentMediaMapper;
    private final ContentMediaPictureMapper contentMediaPictureMapper;
    private final ContentMediaVideoMapper contentMediaVideoMapper;
    private final GreenRpcService greenRpcService;
    private final TopicService topicService;
    private final ContentTopicMapper contentTopicMapper;
    private final VodRpcService vodRpcService;
    private final MqTemplate mqTemplate;

    public ContentServiceImpl(ContentMapper contentMapper,
                              ContentMediaMapper contentMediaMapper,
                              ContentMediaPictureMapper contentMediaPictureMapper,
                              ContentMediaVideoMapper contentMediaVideoMapper,
                              GreenRpcService greenRpcService,
                              TopicService topicService,
                              ContentTopicMapper contentTopicMapper,
                              VodRpcService vodRpcService,
                              MqTemplate mqTemplate){
        this.contentMapper = contentMapper;
        this.contentMediaMapper = contentMediaMapper;
        this.contentMediaPictureMapper = contentMediaPictureMapper;
        this.contentMediaVideoMapper = contentMediaVideoMapper;
        this.greenRpcService = greenRpcService;
        this.topicService = topicService;
        this.contentTopicMapper = contentTopicMapper;
        this.vodRpcService = vodRpcService;
        this.mqTemplate = mqTemplate;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long createContent(ContentCreateReqDTO contentCreateReqDTO) {
        if (StringUtils.isEmpty(contentCreateReqDTO.getCoverFileId())){
            if (!CollectionUtils.isEmpty(contentCreateReqDTO.getPictureFileIdList())){
                contentCreateReqDTO.setCoverFileId(contentCreateReqDTO.getPictureFileIdList().get(0));
            }
        }
        if (!StringUtils.isEmpty(contentCreateReqDTO.getTitle())) {
            R<String> greenResult = greenRpcService.greenSync(GreenRequestDTO.builder().dataType(MimeTypeEnum.TEXT.name()).value(contentCreateReqDTO.getTitle()).build());
            ApiAssetUtil.isTrue(SuggestionTypeEnum.PASS.name().equals(greenResult.getData()), GeneralErrorEnum.VIDEO_TITLE_REVIEW_BLOCKED);
        }
        List<ContentTitleItem> contentTitleList = BeanUtil.prepare(contentCreateReqDTO.getContentTitleItemList(), ContentTitleItem.class);
        Content content = Content.builder().customerId(contentCreateReqDTO.getCustomerId()).itemType(contentCreateReqDTO.getItemType()).title(contentCreateReqDTO.getTitle())
                .coverFileId(contentCreateReqDTO.getCoverFileId()).build();
        if (!contentTitleList.isEmpty()){
            content.setTitleJson(JsonUtil.toJSONString(contentTitleList));
        }
        contentMapper.insert(content);
        insertContentTopic(contentCreateReqDTO, contentTitleList, content);
        insertContentMedia(contentCreateReqDTO, content);
        addGreen(contentCreateReqDTO, content);
        return content.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void onContentReview(ContentGreenResultDTO contentReviewResultDTO){
        log.info("on content review, id:{} suggestion:{}", contentReviewResultDTO.getExtra(), contentReviewResultDTO.getSuggestion());
        var content = getContent(ContentQuery.builder().id(Long.parseLong(contentReviewResultDTO.getExtra())).build());
        if (content == null){
            log.error("no content find, id:{}", contentReviewResultDTO.getExtra());
            return;
        }
        if (content.getDeleted()){
            return;
        }
        ContentStatusEnum videoStatus = SuggestionTypeEnum.BLOCK.name().equals(contentReviewResultDTO.getSuggestion()) ? ContentStatusEnum.UNPUBLISH : ContentStatusEnum.PUBLISH;
        content.setReviewed(true);
        var videoTopics = list(ContentTopicQuery.builder().contentId(content.getId()).build());
        if (ContentStatusEnum.PUBLISH == videoStatus){
            //            R<MediaInfoDTO> mediaInfo = vodRpcService.getMediaInfo(content.getFileId());
//            if (mediaInfo.getData() == null){
//                return;
//            }
//            content.setDuration(mediaInfo.getData().getDuration());
        }
        contentMapper.updateById(content);
        videoTopics.forEach(item -> {
            item.setStatus(content.getStatus());
            contentTopicMapper.updateById(item);
        });
    }

    @Override
    public PageList<Content> listMyContent(ContentMyReqDTO contentMyReqDTO) {
        ContentQuery contentQuery = ContentQuery.builder().customerId(contentMyReqDTO.getCustomerId()).deleted(false).itemType(contentMyReqDTO.getItemType()).customerIdList(contentMyReqDTO.getCustomerIdList())
                .pageLimit(PageHelper.toPageLimit(contentMyReqDTO.getPageDomain())).build();
        if (contentMyReqDTO.getPageDomain().getCursor() > 0){
            contentQuery.setLtId(contentMyReqDTO.getPageDomain().getCursor());
        }
        if (!Objects.equals(contentMyReqDTO.getCustomerId(), contentMyReqDTO.getSessionCustomerId())){
            contentQuery.setStatus(ContentStatusEnum.PUBLISH.getValue());
        }
        LambdaQueryWrapper<Content> queryWrapper = build(contentQuery);
        queryWrapper.orderByDesc(Content::getTopValue).orderByDesc(Content::getId);
        List<Content> contentList = contentMapper.selectList(queryWrapper);
        if (contentList.isEmpty()){
            return new PageList<>();
        }
        return new PageList<>(contentList, contentMyReqDTO.getPageDomain().getPageSize(), CollectionUtils.lastElement(contentList).getId());
    }

    @Override
    public Map<Integer, Integer> listMyContentTotalCount(ContentMyTotalReqDTO contentMyTotalReqDTO) {
        Map<Integer, Integer> result = new HashMap<>();
        ContentQuery contentQuery = ContentQuery.builder().customerId(contentMyTotalReqDTO.getCustomerId()).deleted(false).build();
        if (!Objects.equals(contentMyTotalReqDTO.getCustomerId(), contentMyTotalReqDTO.getSessionCustomerId())){
            contentQuery.setStatus(ContentStatusEnum.PUBLISH.getValue());
        }
        contentMyTotalReqDTO.getItemType().stream().forEach(item -> {
            contentQuery.setItemType(item);
            Integer count = contentMapper.selectCount(build(contentQuery)).intValue();
            result.put(item, count);
        });
        return result;
    }

    @Override
    public List<ContentMedia> listContentMedia(List<Long> contentIdList) {
        return list(ContentMediaQuery.builder().contentIdList(contentIdList).build());
    }

    @Override
    public List<ContentMediaPicture> listContentMediaPicture(List<Long> contentIdList) {
        return list(ContentMediaPictureQuery.builder().contentIdList(contentIdList).build());
    }

    @Override
    public List<ContentMediaVideo> listContentMediaVideo(List<Long> contentIdList) {
        return list(ContentMediaVideoQuery.builder().contentIdList(contentIdList).build());
    }

    @Override
    public List<Content> listContent(List<Long> idList) {
        return list(ContentQuery.builder().idList(idList).build());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteContent(List<Long> idList, Long customerId) {
        List<Content> contents = list(ContentQuery.builder().idList(idList).customerId(customerId).build());
        if (contents.isEmpty()){
            return;
        }
        List<ContentTopic> contentTopics = list(ContentTopicQuery.builder().contentIdList(idList).build());
        contentTopics.stream().forEach(item ->{
            item.setDeleted(true);
            contentTopicMapper.updateById(item);
        });
        contents.stream().forEach(item ->{
            item.setDeleted(true);
            contentMapper.updateById(item);
        });
    }

    private void insertContentTopic(ContentCreateReqDTO contentCreateReqDTO, List<ContentTitleItem> videoTitleList, Content video) {
        final List<ContentTitleItem> needCreteVideoTopic = videoTitleList.stream().filter(item -> ContentTitleItemTypeEnum.TOPIC.getValue().equals(item.getVideoTitleType()) &&
                (item.getKey() == null || item.getKey() <= 0 ))
                .collect(Collectors.toList());
        if (!needCreteVideoTopic.isEmpty()){
            final Map<String, Topic> createdTopic = topicService.listOrCreateTopics(new ArrayList<>(needCreteVideoTopic.stream().map(item -> item.getText()).collect(Collectors.toSet())), contentCreateReqDTO.getItemType()).stream()
                    .collect(Collectors.toMap(item -> item.getTitle(), item -> item));
            needCreteVideoTopic.stream().forEach(item -> {
                item.setKey(createdTopic.get(item.getKey()).getId());
            });
        }
        needCreteVideoTopic.stream().filter(item -> ContentTitleItemTypeEnum.TOPIC.getValue().equals(item.getVideoTitleType())).forEach(item -> {
            contentTopicMapper.insert(ContentTopic.builder().topicId(item.getKey()).contentId(video.getId()).build());
        });
    }

    private void insertContentMedia(ContentCreateReqDTO contentCreateReqDTO, Content video) {
        HashMap<Long, ContentMediaPicture> contentPictureMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(contentCreateReqDTO.getPictureFileIdList())){
            contentCreateReqDTO.getPictureFileIdList().stream().forEach(item ->{
                ContentMedia contentMedia = ContentMedia.builder().contentId(video.getId()).customerId(video.getCustomerId()).mimeType(MimeTypeEnum.PICTURE.name()).build();
                contentMediaMapper.insert(contentMedia);
                contentMediaPictureMapper.insert(ContentMediaPicture.builder().contentId(video.getId()).contentMediaId(contentMedia.getId()).fileId(item).build());
            });
        }
        if (!CollectionUtils.isEmpty(contentCreateReqDTO.getVideoFileIdList())){
            contentCreateReqDTO.getPictureFileIdList().stream().forEach(item ->{
                ContentMedia contentMedia = ContentMedia.builder().contentId(video.getId()).customerId(video.getCustomerId()).mimeType(MimeTypeEnum.VIDEO.name()).build();
                contentMediaMapper.insert(contentMedia);
                contentMediaVideoMapper.insert(ContentMediaVideo.builder().contentId(video.getId()).contentMediaId(contentMedia.getId()).fileId(item).build());
            });
        }
    }

    private void addGreen(ContentCreateReqDTO contentCreateReqDTO, Content video) {
        List<AddGreenNotifyRequestDTO.ContentDTO> contentList = new ArrayList<>(10);
        if (!CollectionUtils.isEmpty(contentCreateReqDTO.getPictureFileIdList())){
            contentCreateReqDTO.getPictureFileIdList().stream().forEach(item -> {
                contentList.add(new AddGreenNotifyRequestDTO.ContentDTO(item, ContentGroupTypeEnum.OSS.getValue(), MimeTypeEnum.PICTURE.name()));
            });
        }
        if (!StringUtils.isEmpty(video.getCoverFileId())){
//            contentList.add(new AddGreenNotifyRequestDTO.ContentDTO(video.getCoverFileId(), ContentGroupTypeEnum.OSS.getValue(), MimeTypeEnum.PICTURE.name()));
        }
        if (!CollectionUtils.isEmpty(contentCreateReqDTO.getVideoFileIdList())){
            contentCreateReqDTO.getVideoFileIdList().stream().forEach(item -> {
                contentList.add(new AddGreenNotifyRequestDTO.ContentDTO(item, ContentGroupTypeEnum.VOD.getValue(), MimeTypeEnum.VIDEO.name()));
            });
        }
        greenRpcService.addGreenNotifyAsync(AddGreenNotifyRequestDTO.builder().extra(video.getId().toString())
                .notifyUrl(Constants.CONTENT_REVIEW_NOTIFY_RUL)
                .contentList(contentList)
                .build());
    }

    private Content getContent(ContentQuery query){
        return contentMapper.selectOne(build(query));
    }

    private List<Content> list(ContentQuery query){
        return contentMapper.selectList(build(query));
    }

    private List<ContentTopic> list(ContentTopicQuery query){
        return contentTopicMapper.selectList(build(query));
    }

    private List<ContentMedia> list(ContentMediaQuery query){
        return contentMediaMapper.selectList(build(query));
    }

    private List<ContentMediaVideo> list(ContentMediaVideoQuery query){
        return contentMediaVideoMapper.selectList(build(query));
    }

    private List<ContentMediaPicture> list(ContentMediaPictureQuery query){
        return contentMediaPictureMapper.selectList(build(query));
    }

    private void deleteContentMedia(ContentMediaQuery mediaQuery){
        contentMediaMapper.delete(build(mediaQuery));
    }

    private void deleteContentPicture(ContentMediaPictureQuery query){
        contentMediaPictureMapper.delete(build(query));
    }

    private void deleteContentVideo(ContentMediaVideoQuery query){
        contentMediaVideoMapper.delete(build(query));
    }

    private LambdaQueryWrapper<Content> build(ContentQuery contentQuery){
        LambdaQueryWrapper<Content> queryWrapper = new LambdaQueryWrapper<>();
        if (contentQuery.getId() != null){
            queryWrapper.eq(Content::getId, contentQuery.getId());
        }
        if (!CollectionUtils.isEmpty(contentQuery.getIdList())){
            queryWrapper.in(Content::getId, contentQuery.getIdList());
        }
        if (contentQuery.getCustomerId() != null){
            queryWrapper.eq(Content::getCustomerId, contentQuery.getCustomerId());
        }
        if (contentQuery.getItemType() != null){
            queryWrapper.eq(Content::getItemType, contentQuery.getItemType());
        }
        if (contentQuery.getDeleted() != null){
            queryWrapper.eq(Content::getDeleted, contentQuery.getDeleted());
        }
        if (contentQuery.getStatus() != null){
            queryWrapper.eq(Content::getStatus, contentQuery.getStatus());
        }
        if (contentQuery.getLtId() != null){
            queryWrapper.lt(Content::getId, contentQuery.getLtId());
        }
        if (contentQuery.getGtId() != null){
            queryWrapper.gt(Content::getId, contentQuery.getGtId());
        }
        if (contentQuery.getPageLimit() != null){
            queryWrapper.last(PageHelper.toPageLimitSql(contentQuery.getPageLimit()));
        }
        if (!CollectionUtils.isEmpty(contentQuery.getCustomerIdList())){
            queryWrapper.in(Content::getCustomerId, contentQuery.getCustomerIdList());
        }
        return queryWrapper;
    }

    private LambdaQueryWrapper<ContentTopic> build(ContentTopicQuery query){
        LambdaQueryWrapper<ContentTopic> queryWrapper = new LambdaQueryWrapper<>();
        if (query.getContentId() != null){
            queryWrapper.eq(ContentTopic::getContentId, query.getContentId());
        }
        if (CollectionUtils.isEmpty(query.getContentIdList())){
            queryWrapper.in(ContentTopic::getContentId, query.getContentIdList());
        }
        return queryWrapper;
    }

    private LambdaQueryWrapper<ContentMedia> build(ContentMediaQuery query){
        LambdaQueryWrapper<ContentMedia> queryWrapper = new LambdaQueryWrapper<>();
        if (query.getContentId() != null){
            queryWrapper.eq(ContentMedia::getContentId, query.getContentId());
        }
        if (!CollectionUtils.isEmpty(query.getContentIdList())){
            queryWrapper.in(ContentMedia::getContentId, query.getContentIdList());
        }
        return queryWrapper;
    }

    private LambdaQueryWrapper<ContentMediaPicture> build(ContentMediaPictureQuery query){
        LambdaQueryWrapper<ContentMediaPicture> queryWrapper = new LambdaQueryWrapper<>();
        if (query.getContentId() != null){
            queryWrapper.eq(ContentMediaPicture::getContentId, query.getContentId());
        }
        if (!CollectionUtils.isEmpty(query.getContentIdList())){
            queryWrapper.in(ContentMediaPicture::getContentId, query.getContentIdList());
        }
        return queryWrapper;
    }

    private LambdaQueryWrapper<ContentMediaVideo> build(ContentMediaVideoQuery query){
        LambdaQueryWrapper<ContentMediaVideo> queryWrapper = new LambdaQueryWrapper<>();
        if (query.getContentId() != null){
            queryWrapper.eq(ContentMediaVideo::getContentId, query.getContentId());
        }
        if (!CollectionUtils.isEmpty(query.getContentIdList())){
            queryWrapper.in(ContentMediaVideo::getContentId, query.getContentIdList());
        }
        return queryWrapper;
    }

}
